part of authorized_login;

typedef SuccessCallback = void Function(dynamic value);
typedef FailureCallback = void Function(dynamic value);

class AuthorizedLogin {
  factory AuthorizedLogin() => _sharedInstance();
  static AuthorizedLogin? _instance;

  AuthorizedLogin._();

  static AuthorizedLogin _sharedInstance() {
    _instance ??= AuthorizedLogin._();
    return _instance!;
  }

  final String _defaultName = 'User';

  SignInWithTwitter? twitterLogin;
  GoogleSignIn? googleSignIn;

  Future<void> signInWithTwitter(
      {required String consumerKey,
      required String consumerSecret,
      required Function(dynamic user) callBack,VoidCallback? toast}) async {
    try {
      if (kIsWeb) {
        //todo web登录
        callBack('does not support web');
      } else {
        toast?.call();
        twitterLogin = SignInWithTwitter(
          // Consumer API keys
          consumerKey: consumerKey,
          // Consumer API Secret keys
          consumerSecret: consumerSecret,
        );

        final TwitterLoginResult result = await twitterLogin!.authorize();

        switch (result.status) {
          case TwitterLoginStatus.loggedIn:
            var session = result.session;
            if (session == null || session.userId.isEmpty) {
              callBack('twitter Authorization succeeded,session is null');
              return;
            }
            UserEntity? userEntity = UserEntity(
              displayName: session.username,
              email: session.email,
              username: session.username,
              familyName: session.username,
              givenName: session.username,
              providerKey: session.userId,
              //3368410454
              loginProvider: 'twitter',
            );
            _loginFinished(userEntity, callBack);
            break;
          case TwitterLoginStatus.cancelledByUser:
          case TwitterLoginStatus.error:
            callBack('twitter Authorization failed');
            break;
        }
      }
    } catch (e) {
      callBack('Failed to sign in with Twitter: $e');
    }
  }

  Future<void> signInWithGoogle(Function(dynamic user) callBack) async {
    try {
      googleSignIn = GoogleSignIn();
      final GoogleSignInAccount? googleUser = await googleSignIn!.signIn();
      if (googleUser == null) {
        callBack('Google Authorization failed');
        return;
      }
      // final GoogleSignInAuthentication? googleAuth =
      //     await googleUser.authentication;
      UserEntity? userEntity = UserEntity(
        displayName: googleUser.displayName == null
            ? googleUser.email.substring(0, googleUser.email.lastIndexOf('@'))
            : googleUser.displayName ?? _defaultName,
        email: googleUser.email,
        username: googleUser.displayName,
        familyName: googleUser.displayName,
        givenName: googleUser.displayName,
        providerKey: googleUser.id,
        //107534270914971198201
        loginProvider: 'google',
      );
      _loginFinished(userEntity, callBack);
    } catch (e) {
      callBack('Failed to sign in with Google: $e');
    }
  }

  _loginFinished(
    UserEntity? user,
    Function(dynamic user) callBack,
  ) async {
    if (user == null) {
      callBack('Authorization succeeded,no user information');
      return;
    }
    callBack(user);
  }

  Future<bool> enableApple() async {
    if (Platform.isIOS) {
      return await SignInWithApple.isAvailable();
    }
    return false;
  }

  Future<bool> enableGoogle() async {
    if (Platform.isAndroid) {
      return await GkbGmsAvailability.isGmsAvailable;
    }
    return true;
  }


  String generateNonce([int length = 32]) {
    const charset =
        '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
    final random = Random.secure();
    return List.generate(length, (_) => charset[random.nextInt(charset.length)])
        .join();
  }

  /// Returns the sha256 hash of [input] in hex notation.
  String sha256ofString(String input) {
    final bytes = utf8.encode(input);
    final digest = sha256.convert(bytes);
    return digest.toString();
  }

  Future<void> signInWithApple({required Function(dynamic user) callBack,VoidCallback? toast}) async {
    try {
      final rawNonce = generateNonce();
      final nonce = sha256ofString(rawNonce);
      final appleCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        nonce: nonce,
      );
      toast?.call();
      UserEntity userEntity = UserEntity(
        displayName: appleCredential.email == null
            ? appleCredential.givenName ?? _defaultName
            : appleCredential.email!
                .substring(0, appleCredential.email!.lastIndexOf('@')),
        email: appleCredential.email,
        username: appleCredential.givenName,
        familyName: appleCredential.familyName,
        givenName: appleCredential.givenName,
        providerKey: appleCredential
                .userIdentifier ?? //001711.c29feadf913545f68501a7ff74a2c9e9.0230
            appleCredential.identityToken ??
            '',
        loginProvider: 'apple',
      );
      _loginFinished(userEntity, callBack);
    } catch (e) {
      callBack('Failed to sign in with Apple: $e');
    }
  }

  void signOut() {
    twitterLogin?.logOut();
    googleSignIn?.signOut();
    twitterLogin = null;
    googleSignIn = null;
  }
}
